package core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import common.Card;
import common.Notify;
import common.Sequence;
import common.Service;
import common.Servlet;
import common.Validate;
import dict.BcDict;
import dict.TransactionDict;
import dicts.GlobalDict;
import dicts.PaymentDict;
import entities.TBank;
import entities.TBc;
import entities.TCard;
import entities.TCs;
import entities.TMerchant;
import entities.TMs;
import entities.TSm;
import entities.TSubject;
import entities.TTransaction;
import interfaces.IBankService;
import interfaces.IBcService;
import interfaces.ICardService;
import interfaces.ICsService;
import interfaces.IMerchantService;
import interfaces.IMsService;
import interfaces.ISmService;
import interfaces.ISubjectService;
import interfaces.ITransactionService;
import net.sf.json.JSONObject;
import util.LogUtil;
import utils.DateUtil;
import utils.DigestUtil;
import utils.NumberUtil;
import utils.StringUtil;

public class Balance extends Servlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public synchronized void process(HttpServletRequest request, HttpServletResponse response) throws Exception {

		System.out.println(DateUtil.format(new Date(), DateUtil.DATETIME) + " | 入账补单");

		// 初始化service
		ISubjectService subjectService = (ISubjectService) Service.create(ISubjectService.class);
		IMerchantService merchantService = (IMerchantService) Service.create(IMerchantService.class);
		ICardService cardService = (ICardService) Service.create(ICardService.class);
		IBankService bankService = (IBankService) Service.create(IBankService.class);
		ITransactionService transactionService = (ITransactionService) Service.create(ITransactionService.class);
		IBcService bcService = (IBcService) Service.create(IBcService.class);
		ICsService csService = (ICsService) Service.create(ICsService.class);
		ISmService smService = (ISmService) Service.create(ISmService.class);
		IMsService msService = (IMsService) Service.create(IMsService.class);

		JSONObject jsonResult = new JSONObject();

		// 初始化bean和属性
		TBank bank = new TBank();
		TSubject subject = new TSubject();
		TMerchant merchant = new TMerchant();
		TCard card = new TCard();
		TTransaction transaction = new TTransaction();
		TBc bc = new TBc();
		TCs cs = new TCs();
		TSm sm = new TSm();
		TMs ms = new TMs();

		// 校验参数 ( 名称,值,校验模式,边界 )
		List<Object[]> parameterList = Collections.synchronizedList(new ArrayList<Object[]>());
		parameterList.add(new Object[] { "bcNo", request.getParameter("bcNo"), Validate.NOTEMPTY | Validate.EXCEEDLENGTH, 0, 50 });
		parameterList.add(new Object[] { "bcRef", request.getParameter("bcRef"), Validate.NOTEMPTY | Validate.EXCEEDLENGTH, 0, 50 });

		JSONObject validateResult = Validate.validate(parameterList);
		LogUtil.balance(Validate.summary(parameterList));

		if (!StringUtil.isEmpty(validateResult)) {
			System.out.println ( validateResult.toString() ) ;
			response.getWriter().print(validateResult.toString());
			return;
		}

		// 校验入账存在和状态
		try {
			bc = bcService.fetch(request.getParameter("bcNo"));
		} catch (Exception e) {
			response.getWriter().print(Validate.result(BcDict.BC_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(BcDict.BC_FETCH_EXCEPTION)));
			return;
		}

		if (bc == null) {
			response.getWriter().print(Validate.result(BcDict.BC_NOT_EXIST, TransactionDict.MESSAGES.get(BcDict.BC_NOT_EXIST)));
			return;
		}

		if (bc.getBcState().equals("1")) {
			response.getWriter().print(Validate.result(BcDict.BC_STATUS_EXCEPTION, TransactionDict.MESSAGES.get(BcDict.BC_STATUS_EXCEPTION)));
			return;
		}
		
		// 得到通道对象
		try {
			bank = bankService.fetch(bc.getBnkNo());
		} catch (Exception e) {
			response.getWriter().print(Validate.result(BcDict.BC_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(BcDict.BC_FETCH_EXCEPTION)));
			return;
		}
		if (bank == null) {
			response.getWriter().print(Validate.result(TransactionDict.AGENCY_CONFIGURATION_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.AGENCY_CONFIGURATION_EXCEPTION)));
			return;
		}
		if (!bank.getBnkState().equals("1")) {
			response.getWriter().print(Validate.result(TransactionDict.AGENCY_CLOSED, TransactionDict.MESSAGES.get(TransactionDict.AGENCY_CLOSED)));
			return;
		}

		// 校验交易存在和状态
		try {
			transaction = transactionService.fetch(bc.getTxnNo());
		} catch (Exception e) {
			response.getWriter().print(Validate.result(TransactionDict.TRANSACTION_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.TRANSACTION_FETCH_EXCEPTION)));
			return;
		}

		if (transaction == null) {
			response.getWriter().print(Validate.result(TransactionDict.TRANSACTION_NOT_EXIST, TransactionDict.MESSAGES.get(TransactionDict.TRANSACTION_NOT_EXIST)));
			return;
		}

		if (transaction.getTxnState().equals("1")) {
			response.getWriter().print(Validate.result(TransactionDict.TRANSACTION_STATUS_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.TRANSACTION_STATUS_EXCEPTION)));
			return;
		}
		
		// 校验子账户存在和状态
		try {
			subject = subjectService.fetch(transaction.getTxnNo().substring(0, 6));
		} catch (Exception e) {
			response.getWriter().print(Validate.result(TransactionDict.SUBJECT_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.SUBJECT_FETCH_EXCEPTION)));
			return;
		}

		if (subject == null) {
			response.getWriter().print(Validate.result(TransactionDict.SUBJECT_NOT_EXIST, TransactionDict.MESSAGES.get(TransactionDict.SUBJECT_NOT_EXIST)));
			return;
		}

		if (!subject.getSubState().equals("1")) {
			response.getWriter().print(Validate.result(TransactionDict.SUBJECT_STATUS_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.SUBJECT_STATUS_EXCEPTION)));
			return;
		}

		// 交易商户存在和状态
		try {
			merchant = merchantService.fetch(transaction.getMerNo());
		} catch (Exception e) {
			response.getWriter().print(Validate.result(TransactionDict.MERCHANT_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.MERCHANT_FETCH_EXCEPTION)));
			return;
		}

		if (merchant == null) {
			response.getWriter().print(Validate.result(TransactionDict.MERCHANT_NOT_EXIST, TransactionDict.MESSAGES.get(TransactionDict.MERCHANT_NOT_EXIST)));
			return;
		}

		if (!merchant.getMerState().equals("1")) {
			response.getWriter().print(Validate.result(TransactionDict.MERCHANT_STATUS_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.MERCHANT_STATUS_EXCEPTION)));
			return;
		}

		// 持卡人存在和状态
		try {
			card = cardService.fetch(transaction.getCrdNo());
		} catch (Exception e) {
			response.getWriter().print(Validate.result(TransactionDict.CARD_FETCH_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.CARD_FETCH_EXCEPTION)));
			return;
		}

		if (card == null) {
			response.getWriter().print(Validate.result(TransactionDict.CARD_NOT_EXIST, TransactionDict.MESSAGES.get(TransactionDict.CARD_NOT_EXIST)));
			return;
		}

		if (!card.getCrdState().equals("1")) {
			response.getWriter().print(Validate.result(TransactionDict.CARD_STATUS_EXCEPTION, TransactionDict.MESSAGES.get(TransactionDict.CARD_STATUS_EXCEPTION)));
			return;
		}

		try {
			bc.setBcRef(request.getParameter("bcRef"));
			bc.setBcMark("blance");
			bc.setBcInfo("success");
			bc.setBcCode(BcDict.BC_SUCCESS);
			bc.setBcMessage(TransactionDict.MESSAGES.get(BcDict.BC_SUCCESS));
			bc.setBcState("1");
			bc.setBcDate(new Date());
			bc.setBcCstate("1");
			bc.setBcCdate(new Date());
			bcService.persist(bc);
		} catch (Exception e) {
			response.getWriter().print(Validate.result(BcDict.BC_PROCESS_EXCEPTION, TransactionDict.MESSAGES.get(BcDict.BC_PROCESS_EXCEPTION)));
			return;
		}

		// 提交上游处理完成后根据收单状态进行清结算
		if (bc.getBcState().equals("1")) {
			if (merchant.getMerShipping().equals("1")) {
				transaction.setTxnLogic("1");
			}
			transaction.setTxnState("1");
			transactionService.persist(transaction);

			cs.setCsNo(Sequence.csSequence());
			cs.setCrdNo(card.getCrdNo());
			cs.setTxnNo(transaction.getTxnNo());
			cs.setCsType(PaymentDict.CS_DEALAGE);
			cs.setCsAmount(transaction.getTxnAmount());
			cs.setCsState("1");
			cs.setCsDate(new Date());
			csService.persist(cs);

			cs.setCsNo(Sequence.csSequence());
			cs.setCrdNo(card.getCrdNo());
			cs.setTxnNo(transaction.getTxnNo());
			cs.setCsType(PaymentDict.CS_MARKUP);
			cs.setCsAmount(NumberUtil.sub(bc.getBcAmount(), transaction.getTxnAmount()));
			cs.setCsState("1");
			cs.setCsDate(new Date());
			csService.persist(cs);

			sm.setSmNo(Sequence.smSequence());
			sm.setMerNo(merchant.getMerNo());
			sm.setTxnNo(transaction.getTxnNo());
			sm.setSmType(PaymentDict.SM_THANSFER);
			sm.setSmAmount(transaction.getTxnAmount());
			sm.setSmState("1");
			sm.setSmDate(new Date());
			smService.persist(sm);

			ms.setMsNo(Sequence.msSequence());
			ms.setMerNo(merchant.getMerNo());
			ms.setTxnNo(transaction.getTxnNo());
			ms.setMsType(PaymentDict.MS_POUNDAGE);
			ms.setMsAmount(NumberUtil.mul(transaction.getTxnAmount(), NumberUtil.div(Card.toPoundage(card.getCrdNumber(), merchant), new Double(100), 4)));
			ms.setMsState("1");
			ms.setMsDate(new Date());
			msService.persist(ms);

			ms.setMsNo(Sequence.msSequence());
			ms.setMerNo(merchant.getMerNo());
			ms.setTxnNo(transaction.getTxnNo());
			ms.setMsType(PaymentDict.MS_MORTGAGE);
			ms.setMsAmount(NumberUtil.mul(transaction.getTxnAmount(), NumberUtil.div(Card.toMortgage(card.getCrdNumber(), merchant), new Double(100), 4)));
			ms.setMsState("1");
			ms.setMsDate(new Date());
			msService.persist(ms);

			sm.setSmNo(Sequence.smSequence());
			sm.setMerNo(merchant.getMerNo());
			sm.setTxnNo(transaction.getTxnNo());
			sm.setSmType(PaymentDict.SM_MORTGAGE);
			sm.setSmAmount(NumberUtil.mul(transaction.getTxnAmount(), NumberUtil.div(Card.toMortgage(card.getCrdNumber(), merchant), new Double(100), 4)));
			sm.setSmState("0");
			sm.setSmDate(new Date(new Date().getTime() + NumberUtil.mul(merchant.getMerReturn(), GlobalDict.DAY.doubleValue()).longValue()));
			smService.persist(sm);
		}

		jsonResult.put("version", GlobalDict.VERSION);
		jsonResult.put("no", subject.getSubNo());
		jsonResult.put("transaction", transaction.getTxnNo());
		jsonResult.put("order", transaction.getTxnOrder());
		jsonResult.put("cur", transaction.getTxnCur());
		jsonResult.put("loc", NumberUtil.transfer(transaction.getTxnLoc()));
		jsonResult.put("rate", NumberUtil.transfer(transaction.getTxnRate(), 4));
		jsonResult.put("amount", NumberUtil.transfer(transaction.getTxnAmount()));
		jsonResult.put("issue", bank.getBnkBill());
		jsonResult.put("signature", DigestUtil.sha256(jsonResult.getString("no") + jsonResult.getString("order") + subject.getSubKey()));
		// 如果交易失败
		if (transaction.getTxnState().equals("0")) {
			jsonResult.put("code", bc.getBcCode());
			jsonResult.put("message", bc.getBcMessage());
			// 设置了失败通知
			if (merchant.getMerNotifying().equals("1")) {
				Notify.assembly(transaction.getTxnNotify(), jsonResult);
				LogUtil.notify ( Notify.redirect ( transaction.getTxnNotify(), jsonResult ) );
			}
			response.getWriter().print(jsonResult.toString());
			return;
		}
		// 如果交易成功
		jsonResult.put("code", TransactionDict.TRANSACTION_SUCCESS);
		jsonResult.put("message", TransactionDict.MESSAGES.get(TransactionDict.TRANSACTION_SUCCESS));
		Notify.assembly(transaction.getTxnNotify(), jsonResult);
		LogUtil.notify ( Notify.redirect ( transaction.getTxnNotify(), jsonResult ) );

		response.getWriter().print(jsonResult.toString());
		return;
	}

}
